/*
 * REFIOEventService.h
 *
 *  Created on: May 29, 2013
 *      Author: Lucifer
 */

#ifndef REFIOSERVICE_H_
#define REFIOSERVICE_H_

namespace BFX
{

class REFIOEventContext;
typedef	REFWrapper<Queue<REF<REFIOEventContext> > >	REFIOEventContextQueue;
typedef	Delegate<void (REFIOEventContext*)>	IOEventCallback;

class REFIOEventDispatcher;

////////////////////////////////////////////////////////////////////////////////
// REFIOEventService

#ifdef	BFX_IO_HAS_IOCP

class REFIOEventService : public REFObject
{
public:
	REFIOEventService(int nNumConcurrentThreads = -1);
	virtual ~REFIOEventService();

	void Shutdown();

	// Request invocation of the given completion. Assumes that WorkStarted() was previously called for the operations.
	void PostDeferredCompletion(REFIOEventContext* pContext);

	// Run the event loop until stopped or no more works.
	int Run();
	// Run until stopped or one operation is performed.
	bool RunOnce();

	// Request to stop the event processing loop.
	void Stop();
	// Reset in preparation for a subsequent run invocation.
	void Restart();

	// Increases number of outstanding works.
	void WorkStarted();
	// Decreases number of outstanding works.
	void WorkFinished();

	// This method binds the Socket win32 handle to the service's CompletionPort (make sure we only bind once per socket).
	void BindToCompletionPort(HANDLE handle);

	// Called after starting an overlapped I/O operation that did not complete immediately.
	void OnPending(REFIOEventContext* pContext);

	// Called after starting an overlapped I/O operation that completed immediately.
	void OnCompletion(REFIOEventContext* pContext, DWORD dwLastError, DWORD dwBytesTransferred);

private:
	enum CONSTANTS
	{
		// Timeout to uses for GetQueuedCompletionStatus. some versions of windows have a "bug" where a call to
		// GetQueuedCompletionStatus can appear stuck even though there are events waiting on the queue. Using a
		// timeout helps to work around the issue.
		WAITING_MAX_TIMEOUT,

		// Completion key value to indicate that an operation has posted with the original dwLastError and dwBytesTransferred
		// values stored in the fields of the OVERLAPPED structure.
		OVERLAPPED_CONTAINS_RESULT,

		// Completion key value used to wake up a thread to dispatch timers or completed operations.
		WAKE_FOR_DISPATCH,
	};

	int		m_nNumConcurrentThreads;

	HANDLE	m_hCompletion;
	long	m_lStopped;					// Flag to indicates whether the event loop has been stopped.
	long	m_lShutdown;				// Flag to indicates whether the service has been shut down.

	long	m_lNumOutstandingWorks;		// The number of unfinished works.

	Mutex	m_mutex;
	long	m_lDispatchRequired;
	List<REF<REFIOEventContext> >	m_completedContexts;		// The queue of handlers that are ready to be delivered.
};

#else	//	BFX_IO_HAS_IOCP

class REFIOEventService : public REFObject
{
public:
	REFIOEventService(int nNumConcurrentThreads = -1);
	virtual ~REFIOEventService();

	void Shutdown();

	void PostImmediateCompletion(REFIOEventContext* pContext);

	// Request invocation of the given completion. Assumes that WorkStarted() was called previously.
	void PostDeferredCompletion(REFIOEventContext* pContext);

	int Run();
	bool RunOnce();

	void Stop();
	void Restart();

	void WorkStarted();
	void WorkFinished();

	REFIOEventDispatcher* GetEventDispatcher() const;

	void InitializeEventDispatcher();

private:
	// This dummy context uses to enter event dispatching.
	REF<REFIOEventContext> m_pEventDispatchContext;
	REF<REFIOEventDispatcher>	m_pEventDispatcher;
	bool	m_bDispatching;

	int		m_nNumConcurrentThreads;
	bool	m_bShutdown;
	bool	m_bStopped;

	long	m_lNumOutstandingWorks;		// The number of unfinished works.

	SyncBlock	m_syncBlock;
	List<REF<REFIOEventContext> >	m_completedContexts;		// The queue of handlers that are ready to be delivered.
};

#endif	//	BFX_IO_HAS_IOCP

} /* namespace BFX */
#endif /* REFIOSERVICE_H_ */
